const jwt = require('jsonwebtoken');
const { User, Role, UserRegion, sequelize } = require('../models');
const { Op, QueryTypes } = require('sequelize');
const { md5 } = require('../helpers/function');
const chance = require('chance').Chance();
const { v4: uuidv4 } = require('uuid');

class UserService {
	static injector(ctn) {
		return [
			ctn.make('varal.app')
		]
	}
	constructor(app) {
		this.app = app;
	}

	async login(username, password) {
		//.sync创建不存在的表，如果表已存在，则不执行任何操作。{force: true}将删除已存在的表，并根据模型定义重新创建表。
		//await User.sync({ force: true });

		let data = await User.findOne({
			raw: false,

			where: {
				username
			}
		});

		if (!data) throw '用户名不存在';

		if (data.password !== md5(password)) throw '登录密码错误';

		data = data.toJSON();
		delete data.password;

		const { id, fullname, role_id } = data;
		data.token = jwt.sign({ id, username, fullname, role_id }, 'wiseidc', { expiresIn: '24h' });

		return data;
	}

	async password(id, original, latest) {
		const userInfo = await User.findOne({
			where: {
				id
			}
		});

		if (userInfo.password !== md5(original)) throw '原密码错误';

		if (!latest) throw '新密码格式错误';

		userInfo.update({
			password: md5(latest)
		});

		return true;
	}

	async get(filter, page = 1, page_size = 20) {
		const { fullname, phone, status, username, gender, role_id, tree_id, team_id, tree_parent_fullname, team_parent_fullname, create_time } = filter;
		const where = {};
		if (fullname) where['fullname'] = { [Op.like]: `%${fullname}%` };
		if (phone) where['phone'] = { [Op.eq]: phone };

		if (username) where['username'] = { [Op.like]: `%${username}%` };
		if (status) where['status'] = { [Op.eq]: status };
		if (gender) where['gender'] = { [Op.eq]: gender };
		if (role_id) where['role_id'] = { [Op.in]: String(role_id).split(',') };

		where[Op.and] = [];

		//if (tree_parent_fullname) where['$tree_parent.fullname$'] = { [Op.like]: `%${tree_parent_fullname}%` };
		if (tree_parent_fullname) {
			where[Op.and].push({
				[Op.or]: [
					{ '$tree_parent.fullname$': { [Op.like]: `%${tree_parent_fullname}%` } },
					{ '$tree_parent.phone$': { [Op.like]: `%${tree_parent_fullname}%` } }
				]
			})
		}
		if (team_parent_fullname) {
			//where['$team_parent.fullname$'] = { [Op.like]: `%${team_parent_fullname}%` };
			where[Op.and].push({
				[Op.or]: [
					{ '$team_parent.fullname$': { [Op.like]: `%${team_parent_fullname}%` } },
					{ '$team_parent.phone$': { [Op.like]: `%${team_parent_fullname}%` } }
				]
			})
		}

		if (create_time?.length) {
			where[Op.and].push(sequelize.where(sequelize.fn('date_format', sequelize.col('User.create_time'), '%Y-%m-%d'), {
				[Op.between]: create_time
			}));
		}

		if (tree_id || team_id) {
			const _where = [];
			if (tree_id) _where.push({ 'tree_id': tree_id });
			if (team_id) _where.push({ 'team_id': team_id });

			if (!where[Op.and]) where[Op.and] = [];

			where[Op.and].push({
				[Op.or]: _where
			});
		}

		/*
		!!!当include: ['regions']时，使用$$条件检索会报错，可能是由于User.hasMany(UserRegions)一对多导致的。
		*/
		const { count: total, rows: data } = await User.findAndCountAll({
			attributes: { exclude: ['password'] },
			/*
			include: ['tree_parent'],
			*/
			include: [{
				attributes: [
					'username', 'nickname', 'fullname', 'phone'
					/*
					[sequelize.literal(`(case
	when ifnull(tree_parent.fullname, '')!='' then tree_parent.fullname
	when ifnull(tree_parent.nickname, '')!='' then tree_parent.nickname
	else tree_parent.username
end)`), 'username']
*/
				],

				model: User,
				as: 'tree_parent',
				/*
				where: (() => {
					return null;
				})()
				*/
			}, {
				attributes: [
					'username', 'nickname', 'fullname', 'phone'
					/*
					[sequelize.literal(`(case
	when ifnull(team_parent.fullname, '')!='' then team_parent.fullname
	when ifnull(team_parent.nickname, '')!='' then team_parent.nickname
	else team_parent.username
end)`), 'username']
*/
				],

				model: User,
				as: 'team_parent',
				/*
				where: (() => {
					return null;
				})()
				*/
			}, {
				model: Role,
				as: 'role',
				attributes: ['name']
			}],
			where,
			order: [
				['id', 'asc']
			],
			...(page_size === Infinity ? {} : {
				offset: (page - 1) * page_size,
				limit: page_size * 1,
			})
		});

		return {
			data,
			total
		}
	}

	async info(where) {
		const user = await User.findOne({
			include: [{
				model: Role,
				as: 'role',
				attributes: ['name', 'auth']
			}, 'regions'],

			where
		});

		return user;
	}

	async delete(id) {
		const users = await User.findAll({
			where: {
				id: { [Op.in]: String(id).split(',') }
			}
		});

		users.forEach((user) => {
			user.destroy();
		});

		return true;
	}

	async save(params) {
		['create_time', 'update_time', 'delete_time'].forEach((d) => {
			delete params[d];
		});

		if (params.password) params.password = md5(params.password);
		if (!params.username && params.phone) params.username = params.phone;

		const { id } = params;

		//判断用户名是否已存在
		const { username = '', phone = '' } = params;
		const valid = await User.findOne({
			where: {
				[Op.or]: [
					{ username },
					{ phone }
				],
				id: { [Op.ne]: id || 0 }
			}
		});

		if (valid) {
			if (username) throw '用户名已存在';
			if (phone) throw '手机号已存在';
		}

		let user;

		if (id) {
			//非普通会员自动关闭用户线索
			if (params['role_id'] && params['role_id'] !== 5) params['team_id'] = null;

			await User.update(params, {
				where: {
					id
				}
			});

			user = await User.findByPk(id);
		} else {
			if (!params.password) params.password = md5(chance.string({ length: 32, alpha: true, numeric: true }));

			user = await User.create(params);
		}

		if (params?.regions?.length) {
			const userRegions = [];
			for (const d of params.regions) {
				d._city_id = d.city_id[1] ?? '';

				if (d.id) {
					await UserRegion.update(d, {
						where: {
							id: d.id
						}
					});
					userRegions.push(await UserRegion.findByPk(d.id));
				} else {
					userRegions.push(await UserRegion.create(d));
				}
			};
			await user.setRegions(userRegions);
		}

		return user;

		//fields: await User.describe().then((params) => Object.keys(params))
	}

	async loginByPhone(phone, open_id = '', scene = '') {
		let data = await User.findOne({
			raw: false,

			where: {
				phone
			}
		});

		//获取推荐人
		let tree_id = 0;
		if (scene) {
			tree_id = await User.findOne({ where: { open_id: scene } }).then((data) => {
				return data.id || 0;
			});
		}

		if (!data) {
			data = await User.create({
				username: phone,
				nickname: phone.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"),
				phone,
				open_id,

				//普通会员
				role_id: 5,
				head_img_url: 'https://mp.kachewo.com/uploadfile/202310/wqpaa7CSdk63SYKLtkKOTIzPEpTfCZZr.png',

				tree_id
			});
		} else {
			if (open_id) {
				await User.update({
					open_id
				}, {
					where: {
						phone
					}
				});
			}
		}

		data = data.toJSON();
		delete data.password;

		const { id, role_id } = data;
		data.token = jwt.sign({ id, role_id }, 'wiseidc', { expiresIn: '24h' });

		return data;
	}
}

exports = module.exports = UserService;
